#include "stdafx.h"


#define _CRT_SECURE_NO_WARNINGS 1
#define TRUE 1
#define FALSE 0
#define FILE_ERROR 0
/*#define DEF_HISTORY_TIME_LIMIT (35 * 60)*/
#define DECREMENT_HISTORY_TIME_LIMIT 1
// #define HISTORY_START_FOUND 2
// #define    HISTORY_END_FOUND 3
#define REAL_TIME_DATA_SIZE 199



const char strCaption[] = "LogFile filter";
const char strSection[] = "LogFile";
const char strFilename[] = "filename";
const char strBinaryMode[] = "binarymode";
const char strWatts[] = "watts";
static char *ptrWatts;


#define BUFSIZE 4096 

static char init_file_name[] = "ccterm.ini";
static char LogFilename[MAX_PATH];
static char error_log_file_name[] = "ccmeter-log.txt";
static char history_file_name[] = "cchistory.txt";
static char archive_dir[MAX_PATH];
static char com_port[12];
static BOOL BinaryMode;
static FILE *fpCCmeter;
static FILE *fpHistory;
static FILE *fpLog;
static FILE *fpCcinit;
static BOOL LogTested;



static double watts_5_min_interval_count = 0;
static double watts_5_min_average;
static double watts_sub_total = 0;
static int in_session = FALSE;
static int in_5th_minute = FALSE;
static int no_history_dump = FALSE;

static int history_running = FALSE;
static int timer_running = FALSE;
static time_t t_hist_start;
static struct tm tm_hist_start;
static int history_time_limit;
static int static_history_time_limit;
static int history_end = FALSE;
static int days_to_archive = 0;

int init_params()
{
    char buffer[MAX_PATH];
    char s_history_time_limit[MAX_PATH];
    char *token;
    int return_status = TRUE;

    errno = 0;

    fpCcinit = fopen(init_file_name,"r");
    if (fpCcinit == NULL)
    {
        fprintf (fpLog,"Error opening INIT File - %s - %s\n",init_file_name,strerror(errno));
        fflush(fpLog);
        return FALSE;
    }
    fgets(buffer,sizeof (buffer),fpCcinit);
    token = strtok(buffer,";");
    if(token != NULL)
    {
        strcpy(com_port,token);
    }else {
        return_status = FALSE;
    }
        
    fgets(buffer,sizeof (buffer),fpCcinit);
    token = strtok(buffer,";");
    if(token != NULL)
    {
        strcpy(s_history_time_limit,token);
    }else {
        return_status = FALSE;
    }
    static_history_time_limit = atoi(s_history_time_limit);
    
    fgets(buffer,sizeof (buffer),fpCcinit);
    token = strtok(buffer,";");
    if(token != NULL)
    {
        strcpy(LogFilename,token);
    }else {
        return_status = FALSE;
    }
        
    fgets(buffer,sizeof (buffer),fpCcinit);
    token = strtok(buffer,";");
    if(token != NULL)
    {
        strcpy(archive_dir,token);
    }else {
        return_status = FALSE;
    }
    
    fgets(buffer,sizeof (buffer),fpCcinit);
    token = strtok(buffer,";");
    if(token != NULL)
    {
        days_to_archive = atoi(token);
    }else {
        return_status = FALSE;
    }
    

    /*fgets(buffer,sizeof (buffer),fpCcinit);
    standby_power = atoi(buffer);
    
    fgets(buffer,sizeof (buffer),fpCcinit);
    strcpy(se_input_path,buffer);
    size = strlen(se_input_path);
    se_input_path[size -1] = '\0';

    fgets(buffer,sizeof (buffer),fpCcinit);
    strcpy(se_output_path,buffer);
    size = strlen(se_output_path);
    se_output_path[size -1] = '\0';

    fgets(buffer,sizeof (buffer),fpCcinit);
    strcpy(back_date,buffer);
    size = strlen(back_date);
    back_date[size -1] = '\0';

    fgets(buffer,sizeof (buffer),fpCcinit);
    strcpy(back_date_start,buffer);
    size = strlen(back_date_start);
    back_date_start[size -1] = '\0';

    fgets(buffer,sizeof (buffer),fpCcinit);
    strcpy(back_time_start,buffer);
    size = strlen(back_time_start);
    back_time_start[size -1] = '\0';


    fgets(buffer,sizeof (buffer),fpCcinit);
    strcpy(my_lat,buffer);
    size = strlen(my_lat);
    my_lat[size -1] = '\0';

    fgets(buffer,sizeof (buffer),fpCcinit);
    strcpy(my_long,buffer);
    size = strlen(my_long);
    my_long[size -1] = '\0';

    fgets(buffer,sizeof (buffer),fpCcinit);
    strcpy(my_tz,buffer);
    size = strlen(my_tz);
    my_tz[size -1] = '\0';*/

    fclose(fpCcinit);

    return return_status;

}

int delete_archive_files(void)
{
    int return_status = TRUE;
    time_t time_now;
    struct tm *past;
    time_t archive_time_seconds;
    int archive_hour = 1;
    char archive_delete_name[MAX_PATH];


    
    time(&time_now);
        
    archive_time_seconds = time_now - (86400 * days_to_archive);
    past = localtime(&archive_time_seconds);

    while(archive_hour < 24){
        sprintf(archive_delete_name,"%s\\cchistory-%d%02d%02d-%02d.txt",
                    archive_dir,(past->tm_year + 1900),(past->tm_mon + 1),past->tm_mday,archive_hour);
        remove(archive_delete_name);
        archive_hour = archive_hour + 2;
    }
    return return_status;
}



void get_time(char *time_now)
{
    time_t tim;
    struct tm *now;
    char *my_time;
    int size;

    time(&tim);
    now=localtime(&tim);
    my_time = asctime(now);
    size = (int) strlen(my_time);
    my_time[size - 1] = ':';
    my_time[size] = ' ';
    my_time[size + 1] = '\0';
    strcpy(time_now,my_time);
}


void print_time(void)
{
    time_t tim;
    struct tm *now;
    char *my_time;
    char s_my_time[80];
    int size;

    time(&tim);
    now=localtime(&tim);
    my_time = asctime(now);
    size = (int) strlen(my_time);
    my_time[size - 1] = '\0';
    strcpy(s_my_time,my_time);
    fprintf(fpLog,"%s: ",s_my_time);
    fflush(fpLog);
}


int get_watts(char *data, double *watts_1, double *watts_2)
{
    int status = FALSE;
    char *watts_ptr;
    char *next_watts;
    char watts_value[10];
    char *watts_end_ptr;
    int watts_length;

    watts_ptr = strstr(data,"<watts>");
    watts_end_ptr = strstr(data,"</watts>");
    watts_ptr = watts_ptr + strlen("<watts>");
    watts_length = (int)(watts_end_ptr - watts_ptr);
    strncpy(watts_value,watts_ptr,watts_length);
    watts_value[watts_length] = '\0';
    *watts_1 = atof(watts_value);

    next_watts = watts_end_ptr + strlen("</watts>");
    watts_ptr = strstr(next_watts,"<watts>");
    watts_end_ptr = strstr(next_watts,"</watts>");
    watts_ptr = watts_ptr + strlen("<watts>");
    watts_length = (int) (watts_end_ptr - watts_ptr);
    strncpy(watts_value,watts_ptr,watts_length);
    watts_value[watts_length] = '\0';
    *watts_2 = atof(watts_value);
    
    return status;
}

int check_history_timer(int current_status,int history_end)
{
    int return_status;
    time_t t_hist_now;
    struct tm *now;
    char new_history_name[MAX_PATH];
    char previous_history_name[MAX_PATH];
    char archive_history_name[MAX_PATH];
    char *token;
    int rename_status;

    return_status = current_status;
    if(timer_running)
    {
        return_status = TRUE;
        t_hist_now = time(NULL);
        now = localtime(&t_hist_now);

        if(history_end)
        {
            fclose(fpHistory);
            return_status = FALSE;
            timer_running = FALSE;
            history_time_limit = static_history_time_limit * 60;
            print_time();
            fprintf(fpLog,"End of History Dump Detected. History Timer Reset. History Dump Complete. History Dump File Closed\n");
            strcpy(previous_history_name,history_file_name);
            token = strtok(previous_history_name,".");
            sprintf(new_history_name,"%s-%d%02d%02d-%02d.txt",
                token,(now->tm_year + 1900),(now->tm_mon + 1),now->tm_mday,now->tm_hour);
            
            errno = 0;
            sprintf(archive_history_name,"%s\\%s",archive_dir,new_history_name);
            rename_status = rename(history_file_name,archive_history_name);
            print_time();
            if(rename_status == 0)
            {
                
                fprintf(fpLog,"History File Renamed to %s\n",archive_history_name);
            }else{
                fprintf(fpLog,"History File Rename Failed: %s.  Old File Name: %s  New File Name: %s\n",
                                                                        strerror(errno),history_file_name,archive_history_name);
            }
        }else{
            history_time_limit = history_time_limit - DECREMENT_HISTORY_TIME_LIMIT;
            if(((t_hist_now - t_hist_start) > history_time_limit) && !history_end)
            {
                fclose(fpHistory);
                return_status = FALSE;
                timer_running = FALSE;
                history_time_limit = static_history_time_limit * 60;
                print_time();
                fprintf(fpLog,"History Timer Expired While Writing History File - !INCREASE HISTORY TIMEOUT VALUE! - History Dump File Closed \n");
            }
        }
    }
    fflush(fpLog);
    return return_status;
}


int write_cc_dump(char *data,int size,int start,int end)
{
    time_t t_hist_now;
    int return_status = FALSE;
    char my_time[80];
    
    if(start)  // start of history dump
    {
        t_hist_start = time(NULL);
        return_status = TRUE;
        /*print_time();
        fprintf(fpLog,"History Dump Started\n");*/
        timer_running = TRUE;
        errno = 0;
        print_time();
        fprintf(fpLog,"Opening History File\n");
        fpHistory = fopen(history_file_name,"w");
        if (fpHistory == NULL)
            {
                print_time();
                fprintf(fpLog,"History File Open Failed: %s",strerror(errno));
                return_status = FALSE;
            }
        history_time_limit = history_time_limit - DECREMENT_HISTORY_TIME_LIMIT;
        print_time();
        fprintf(fpLog,"Writing History Data - Start. History Dump Time Limit: %d seconds\n",history_time_limit);
        get_time(my_time);
        fwrite(my_time,1,(size_t) strlen(my_time),fpHistory);
        fwrite("\n",1,(size_t) strlen("\n"),fpHistory);
        fwrite(data,1,(size_t) size,fpHistory);
        fflush(fpHistory);
        
    }else  // History dump has already started.  The proc - check_history_timer - will check for the end of the history dump
    {
        t_hist_now = time(NULL);
        return_status = TRUE;
        history_time_limit = history_time_limit - DECREMENT_HISTORY_TIME_LIMIT;
        fwrite(data,1,(size_t) size,fpHistory);
        fflush(fpHistory);
        
        if(((t_hist_now - t_hist_start) > history_time_limit) && !end)
        {
            fclose(fpHistory);
            return_status = FALSE;
            timer_running = FALSE;
            print_time();
            history_time_limit = static_history_time_limit * 60;
            fprintf(fpLog,"History Timer Expired While Writing History File - !INCREASE HISTORY TIMEOUT VALUE! - History Dump File Closed \n");
        }
    }
    fflush(fpLog);
    return return_status;
}

int history_end_check(char *data,int size)
{
    char *temp_check;
    int status = FALSE;
    temp_check = strstr(data,"</m001>");
    if(temp_check != NULL)
    {
        status = TRUE;
    }
    return status;
}
        
int history_check(char *data,int size)
{
    char *temp_check;
    int status = FALSE;
    temp_check = strstr(data,"<hist>");
    if(temp_check != NULL)
    {
        status = TRUE;
    }
    return status;
}
    
int real_time_check(char *data,int size)
{
    char *temp_check;
    int status = FALSE;
    if(size == REAL_TIME_DATA_SIZE){
        temp_check = strstr(data,"tmpr");
        if(temp_check != NULL)
        {
            status = TRUE;
        }
    }
    return status;
}


int flt_Receive(char *Text, int Size)
{
    int watts_status = FALSE;
    int real_time_data = FALSE;
    int history_data = FALSE;
    int return_status = FALSE;
    
    static double i_watts_1 = 0;
    static double i_watts_2 = 0;
    static double i_watts_total = 0;
    static int history_status = FALSE;
    static int reported_5_minute_data = FALSE;
    static int in_5th_minute = FALSE;
    static int just_started = TRUE;
    // static int raw_read_count = 0;
    char my_time[80];

    // print_time();
    // raw_read_count++;
    // fprintf(fpLog,"Raw Read Count: %d\n",raw_read_count);
    // fflush(fpLog);
    

/*    if (real_time_data) 
    {
        time_t tim=time(NULL);
        struct tm *now=localtime(&tim);

        if(now->tm_min%5 != 0)
        {
            if(the_5th_minute_started)
            {
                watts_5_min_average = watts_sub_total / watts_5_min_interval_count;
                get_time(my_time);
                fprintf(fpLog,"%sReal Time Data - 5 Minute Report: Watts-SubTotal: %6.2f Watts Interval Count: %5.2f  Watts AVG: %5.2f\n",
                            my_time,watts_sub_total,watts_5_min_interval_count,watts_5_min_average);
                fflush(fpLog);
                fprintf(fpCCmeter,"%02d.%02d.%d %02d:%02d:00;KWHR;%5.2f \n",
                    now->tm_mday,(now->tm_mon + 1),(now->tm_year + 1900), now->tm_hour,(now->tm_min - 1),watts_5_min_average);
                fflush(fpCCmeter);
                watts_sub_total = 0;
                watts_5_min_interval_count = 0;
                history_status = check_history_timer(history_status,history_end);
                return_status = delete_archive_files();
                in_5th_minute = FALSE;
            }else
            {
                just_started = FALSE;
                watts_status = get_watts(Text,&i_watts_1,&i_watts_2);
                i_watts_total = i_watts_1 + i_watts_2;
                watts_5_min_interval_count++;
                watts_sub_total = watts_sub_total + i_watts_total;
            }
        } else {
                if(!just_started)
                {
                    watts_status = get_watts(Text,&i_watts_1,&i_watts_2);
                    i_watts_total = i_watts_1 + i_watts_2;
                    watts_5_min_interval_count++;
                    watts_sub_total = watts_sub_total + i_watts_total;
                    in_5th_minute = TRUE;
                }
        }
    }
    
*/

        // This routine collects the 10 second data and averages it over 5 minutes. It starts at 0 and ends at the beginning of 
        // minute 5. Ex: Minutes 0,1,2,3,4 - At beginning of minute 5 record report.  5,6,7,8,9 - At beginning of minute 10 record report. 
        // This (I believe) coincides with the method Sunny Explorer reports five minute data (such as it reports average power up to
        // the five minute mark. But this is only a guess as SMA is not forthcoming with the exact information.

    real_time_data = real_time_check(Text,Size);
    if (real_time_data){
        time_t tim=time(NULL);
        struct tm *now=localtime(&tim);
        

        if(now->tm_min%5 == 0 || now->tm_min == 0){  // The minute is divisible by 5 or the minute is 0
            if(!just_started){ // The program started in the 5th minute.  The values will not be valid. Skip this first 5th minute.
                if(!reported_5_minute_data){ // At start of 5th minute report the 5 minute data
                    watts_5_min_average = watts_sub_total / watts_5_min_interval_count;
                    get_time(my_time);
                    fprintf(fpLog,"%sReal Time Data - 5 Minute Report: Watts-SubTotal: %6.2f Watts Interval Count: %5.2f  Watts AVG: %5.2f\n",
                            my_time,watts_sub_total,watts_5_min_interval_count,watts_5_min_average);
                    
                    // fprintf(fpLog,"%sReseting Raw Read Count %d\n",my_time,raw_read_count);
                    // raw_read_count = 0;
                    fflush(fpLog);
                    fprintf(fpCCmeter,"%02d.%02d.%d %02d:%02d:00;KWHR;%5.2f \n",
                    now->tm_mday,(now->tm_mon + 1),(now->tm_year + 1900), now->tm_hour,(now->tm_min),watts_5_min_average);
                    fflush(fpCCmeter);
                    watts_sub_total = 0;
                    watts_5_min_interval_count = 0;
                    history_status = check_history_timer(history_status,history_end); // Check for end of history dump
                    return_status = delete_archive_files();  // Delete archived history files based on the init parameter
                    reported_5_minute_data = TRUE;
                    
                } else{ // In the 5th minute.  Collect the 5th minute data
                    watts_status = get_watts(Text,&i_watts_1,&i_watts_2);
                    i_watts_total = i_watts_1 + i_watts_2;
                    watts_5_min_interval_count++;
                    watts_sub_total = watts_sub_total + i_watts_total;
                }
            }
        }else{ // Not in a 5th minute period. 
            just_started = FALSE;
            reported_5_minute_data = FALSE;
            watts_status = get_watts(Text,&i_watts_1,&i_watts_2);
            i_watts_total = i_watts_1 + i_watts_2;
            watts_5_min_interval_count++;
            watts_sub_total = watts_sub_total + i_watts_total;
        }
    }


    if(!no_history_dump){
        history_data = history_check(Text,Size);
        
        if(history_data){
            history_end = history_end_check(Text,Size);
            if(history_status == FALSE){
                history_status = TRUE;
                history_status = write_cc_dump(Text,(int) Size,history_status,history_end);
            }else{
                history_status = FALSE;
                history_status = write_cc_dump(Text,(int) Size,history_status,history_end);
            }
        }
    }
    return TRUE;
}


  
/*int main(int argc, CHAR* argv[])*/
int _tmain(int argc, _TCHAR* argv[])
{
  
    int n = 4096;
    HANDLE hSerial;
    DCB dcbSerialParams = {0};
    COMMTIMEOUTS timeouts={0};
    char szBuff[4096] = {0};
    DWORD dwBytesRead = 0;
    char lastError[1024];
    static BOOL com_read_status = TRUE;

    int status = 0;
    int in_odd_start_hour = FALSE;
    int program_just_started = TRUE;
    time_t tim;
    struct tm *now;
    
    fpLog = fopen(error_log_file_name,"at");
    if(fpLog == NULL)
    {
        perror("CC Log File Open Failed: ");
        printf("Program Terminating\n");
        exit (FALSE);
    }

    
    status = init_params();
    if(!status){
        print_time();
        fprintf(fpLog,"Initialization of Parameters Failed\n");
        fflush(fpLog);
        exit(FALSE);
    }

    errno = 0;
    fpCCmeter = fopen(LogFilename,"at");
    if(fpCCmeter == NULL)
    {
        print_time();
        fprintf(fpLog,"CC Data File Open Failed    with Error: %s   Program Terminating\n",strerror(errno));
        exit(FALSE);
    }

    history_time_limit = static_history_time_limit * 60;
        
    hSerial = CreateFile(com_port,
                GENERIC_READ | GENERIC_WRITE,
                0,
                0,
                OPEN_EXISTING,
                FILE_ATTRIBUTE_NORMAL,
                0);
    if(hSerial==INVALID_HANDLE_VALUE){
        if(GetLastError()==ERROR_FILE_NOT_FOUND)
        {
            print_time();
            fprintf(fpLog,"COM Port: %s Not Found\n",com_port);
            exit (FALSE);
            //serial port does not exist. Inform user.
        }
    FormatMessage(
    FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
    NULL,
    GetLastError(),
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    lastError,
    1024,
    NULL);
    print_time();
    fprintf(fpLog,"Error Opening serial port state %s\n",lastError);
    exit (FALSE);
    }


    dcbSerialParams.DCBlength=sizeof(dcbSerialParams);
    if (!GetCommState(hSerial, &dcbSerialParams)) {
        FormatMessage(
        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        GetLastError(),
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        lastError,
        1024,
        NULL);
        print_time();
        fprintf(fpLog,"Error Retrieving serial port state %s\n",lastError);
        exit(FALSE);
    }

    dcbSerialParams.BaudRate=CBR_57600;
    dcbSerialParams.ByteSize=8;
    dcbSerialParams.StopBits=ONESTOPBIT;
    dcbSerialParams.Parity=NOPARITY;
    if(!SetCommState(hSerial, &dcbSerialParams)){
        FormatMessage(
        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        GetLastError(),
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        lastError,
        1024,
        NULL);
        print_time();
        fprintf(fpLog,"Error Setting serial port state %s\n",lastError);
        exit(FALSE);
    }

    timeouts.ReadIntervalTimeout=20;
    timeouts.ReadTotalTimeoutConstant=50;
    timeouts.ReadTotalTimeoutMultiplier=10;
    timeouts.WriteTotalTimeoutConstant=50;
    timeouts.WriteTotalTimeoutMultiplier=10;

    if(!SetCommTimeouts(hSerial, &timeouts)){
        FormatMessage(
        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        GetLastError(),
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        lastError,
        1024,
        NULL);
        print_time();
        fprintf(fpLog,"Error Setting serial port timeouts %s\n",lastError);
        exit(FALSE);
    }

    print_time();
    fprintf(fpLog,"CCTERM Started and Initialized. History Time Limit is: %d Minutes\n",(history_time_limit / 60));
    fflush(fpLog);

    while(com_read_status){
        if(!(com_read_status = ReadFile(hSerial, szBuff, n, &dwBytesRead, NULL))){
            FormatMessage(
            FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL,
            GetLastError(),
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            lastError,
            1024,
            NULL);
            //print_time();
            //fprintf(fpLog,"Error Reading Com Port %s\n",lastError);
            //CloseHandle(hSerial);
            // exit(FALSE);
        }else {                                             // Check if CCTERM has started in an Odd Hour
            time(&tim);                                        // If so wait until next Odd Hour
            now=localtime(&tim);                            // So to avoid obtaining a partial dump 
            if(now->tm_hour%2 != 0 && program_just_started){
                in_odd_start_hour = TRUE;
                no_history_dump = TRUE;
                program_just_started = FALSE;
                print_time();
                fprintf(fpLog,"CC TERM has started in an Odd Hour.  CC History Dumps will start in the Next Odd Hour\n");
                fflush(fpLog);
            }else{
                program_just_started = FALSE;
                if(in_odd_start_hour)
                {
                    if(now->tm_hour%2 == 0)
                    {
                        in_odd_start_hour = FALSE;
                        no_history_dump = FALSE;
                    }
                }
            }
            flt_Receive(szBuff, (int) dwBytesRead);
        } // End IF ReadFile
    } // End While (com_read_status)
    print_time();                            // If we get this far a read failed on the com port
    fprintf(fpLog,"Error Reading Com Port %s.  Program is terminating\n",lastError);
    CloseHandle(hSerial);
    exit(FALSE);
    
    // CloseHandle(hSerial);
    return;
}

